import datetime
from http.client import HTTPException
import json
from typing import Any

from flask import current_app, make_response, request

from app.vo import BaseVO


class APIException(HTTPException):
    code = 500
    msg = 'sorry, we made a mistake!'
    error_code = 999

    def __json_dumps_default_func(o):
        tp = str(type(o))
        if isinstance(o, list):  # 有些list不是常规的list
            return o
        if isinstance(o, BaseVO):
            return dict(o)
        if hasattr(o, '__dict__'):  # 应该判断属性是否存在
            return o.__dict__
        if isinstance(o, datetime.datetime):
            return o.isoformat().split('T')
        if tp.find('float') != -1:  # 兼容numpy类型
            return float(o)
        if tp.find('array') != -1:  # 兼容numpy类型
            return o.tolist()
        else:
            return o.__dict__

    def __init__(self, msg: Any = None, code=None, error_code=None, headers=None):
        if code:
            self.code = code
        if error_code:
            self.error_code = error_code
        if msg:
            self.msg = msg
        super(APIException, self).__init__(msg, None)

    def get_body(self, environ=None):
        body = dict(
            msg=self.msg,
            error_code=self.error_code,
            request=request.method + ' ' + self.get_url_no_param()
        )
        text = json.dumps(body, default=self.__json_dumps_default_func)
        return text

    def get_headers(self, environ=None):
        """Get a list of headers."""
        return [('Content-Type', 'application/json')]

    @staticmethod
    def get_url_no_param():
        full_path = str(request.full_path)
        main_path = full_path.split('?')
        return main_path[0]

    def response(self):
        response = make_response()
        response.data = self.get_body()
        response.status_code = self.code
        response.content_type = 'application/json'
        response.headers['Access-Control-Allow-Origin'] = current_app.config['ACCESS_CONTROL_ALLOW_ORIGIN']
        return response


class Success(APIException):
    code = 201
    msg = 'ok'
    error_code = 0


class DeleteSuccess(APIException):
    code = 202
    msg = 'delete ok'
    error_code = 1


class UpdateSuccess(APIException):
    code = 200
    msg = 'update ok'
    error_code = 2


class ServerError(APIException):
    code = 500
    msg = 'sorry, we made a mistake!'
    error_code = 999


class ParameterException(APIException):
    code = 400
    msg = 'invalid parameter'
    error_code = 1000


class NotFound(APIException):
    code = 404
    msg = 'the resource are not found'
    error_code = 1001


class AuthFailed(APIException):
    code = 401
    msg = 'authorization failed'
    error_code = 1005


class Forbidden(APIException):
    code = 403
    error_code = 1004
    msg = 'forbidden, not in scope'
